package com.huaxonline.boot.mybatisplus.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.huaxonline.boot.mybatisplus.properties.MetaObjectHandlerProperties;
import com.huaxonline.boot.mybatisplus.provider.CurrentUserProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * MyBatis Plus 自动填充处理器
 * 支持自定义字段名和可扩展的用户获取逻辑
 *
 * @author system
 * @since 1.0.0
 */
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    private final MetaObjectHandlerProperties properties;
    private CurrentUserProvider currentUserProvider;

    @Autowired
    public MyMetaObjectHandler(MetaObjectHandlerProperties properties) {
        this.properties = properties;
    }

    @Autowired(required = false)
    public void setCurrentUserProvider(CurrentUserProvider currentUserProvider) {
        this.currentUserProvider = currentUserProvider;
    }

    /**
     * 插入时自动填充
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.debug("开始插入填充...");

        // 安全填充创建时间
        safeFillField(metaObject, properties.getCreateTimeField(), LocalDateTime.now());

        // 安全填充修改时间
        safeFillField(metaObject, properties.getUpdateTimeField(), LocalDateTime.now());

        // 安全填充创建人
        safeFillField(metaObject, properties.getCreateUserField(), getCurrentUsername());

        // 安全填充修改人
        safeFillField(metaObject, properties.getUpdateUserField(), getCurrentUsername());

        // 安全填充逻辑删除标记
        safeFillField(metaObject, properties.getDeletedField(), 0);
    }

    /**
     * 更新时自动填充
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.debug("开始更新填充...");

        // 强制填充修改时间（更新时必须更新）
        forceFillField(metaObject, properties.getUpdateTimeField(), LocalDateTime.now());

        // 强制填充修改人（更新时必须更新）
        forceFillField(metaObject, properties.getUpdateUserField(), getCurrentUsername());
    }

    /**
     * 安全填充字段，如果字段不存在则跳过
     * 仅在字段为空时填充（用于插入操作）
     */
    private void safeFillField(MetaObject metaObject, String fieldName, Object value) {
        try {
            // 检查字段是否存在
            if (metaObject.hasSetter(fieldName)) {
                // 检查字段是否已经有值
                Object currentValue = metaObject.getValue(fieldName);
                if (currentValue == null) {
                    // 字段存在且为空，进行填充
                    metaObject.setValue(fieldName, value);
                    log.debug("填充字段 {} = {}", fieldName, value);
                } else {
                    log.debug("字段 {} 已有值 {}，跳过填充", fieldName, currentValue);
                }
            } else {
                log.debug("字段 {} 不存在，跳过填充", fieldName);
            }
        } catch (Exception e) {
            log.warn("填充字段 {} 时发生异常: {}", fieldName, e.getMessage());
        }
    }

    /**
     * 强制填充字段，如果字段不存在则跳过
     * 不管字段是否已有值，都会进行填充（用于更新操作）
     */
    private void forceFillField(MetaObject metaObject, String fieldName, Object value) {
        try {
            // 检查字段是否存在
            if (metaObject.hasSetter(fieldName)) {
                // 强制填充，不管原来有没有值
                metaObject.setValue(fieldName, value);
                log.debug("强制填充字段 {} = {}", fieldName, value);
            } else {
                log.debug("字段 {} 不存在，跳过填充", fieldName);
            }
        } catch (Exception e) {
            log.warn("填充字段 {} 时发生异常: {}", fieldName, e.getMessage());
        }
    }

    /**
     * 获取当前用户ID
     * 优先使用自定义的 CurrentUserProvider，否则返回默认值
     */
    private String getCurrentUsername() {
        if (currentUserProvider != null) {
            try {
                String username = currentUserProvider.getCurrentUsername();
                return username != null ? username : "system";
            } catch (Exception e) {
                log.warn("获取当前用户失败: {}", e.getMessage());
                return "system";
            }
        }
        return "system";
    }
}
